package solver

/*
//this is v1.0
func (g *Grid) RowLastOne() (rowNum, colNum, value uint8) {
	for i, row := range g.rows {
		rowNum = uint8(i)
		if row.solvedCount != 8 {
			continue
		}
		for colNum = 0; colNum < 9; colNum++ {
			if row.cells[colNum].value != 0 {
				continue
			}
			for c := uint8(0); c < 9; c++ {
				if c == colNum {
					continue
				}
				row.cells[colNum].removeCandidate(row.cells[c].value)
			}
			for c := uint8(0); c < 9; c++ {
				if !row.cells[colNum].candidates[c] {
					continue
				}
				value = c + 1
				row.cells[colNum].set(value)
				return
			}
		}
	}
	return
}
*/

func UnitLastOne(u House) (num int, value uint8) {
	if u.solvedCount != 8 {
		return
	}

	for num = 0; num < 9; num++ {
		if u.cells[num].value == 0 {
			break
		}
	}

	for i := 0; i < 9; i++ {
		if i == num {
			continue
		}
		u.cells[num].removeCandidate(u.cells[i].value)
	}
	for i := 0; i < 9; i++ {
		if !u.cells[num].candidates[i] {
			continue
		}
		value = uint8(i) + 1
		u.cells[num].set(value)
		return
	}

	return
}

func (g *Grid) RowsLastOne() (rowNum int, colNum int, value uint8) {
	for rowNum = 0; rowNum < 9; rowNum++ {
		colNum, value = UnitLastOne(g.rows[rowNum])
		if value != 0 {
			return
		}
	}
	return
}

func (g *Grid) ColsLastOne() (rowNum int, colNum int, value uint8) {
	for colNum = 0; colNum < 9; colNum++ {
		rowNum, value = UnitLastOne(g.cols[colNum])
		if value != 0 {
			return
		}
	}
	return
}

func (g *Grid) BoxesLastOne() (rowNum int, colNum int, value uint8) {
	var boxNum int
	var cellNum int
	for boxNum = 0; boxNum < 9; boxNum++ {
		cellNum, value = UnitLastOne(g.boxes[boxNum])
		if value != 0 {
			rowNum, colNum = calcRowAndColNum(boxNum, cellNum)
			return
		}
	}
	return
}

func ClearupInUnit(u House, solvedNum int, value uint8) {
	for i := 0; i < 9; i++ {
		if i == solvedNum || u.cells[i].value != 0 {
			continue
		}
		u.cells[i].removeCandidate(value)
	}
}

func (g *Grid) ClearupInRow(solvedRowNum int, solvedColNum int) {
	row := g.rows[solvedRowNum]
	value := g.cells[solvedRowNum][solvedColNum].value
	ClearupInUnit(row, solvedColNum, value)
}

/*
func (g *Grid) ClearupInRow(solvedRowNum int, solvedColNum int) {
	row := g.rows[solvedRowNum]
	value := g.cells[solvedRowNum][solvedColNum].value
	for colNum := 0; colNum < 9; colNum++ {
		if colNum == solvedColNum || row.cells[colNum].value != 0 {
			continue
		}
		row.cells[colNum].removeCandidate(value)
	}
}

func (g *Grid) ClearupInCol(solvedRowNum int, solvedColNum int) {
	col := g.cols[solvedColNum]
	value := g.cells[solvedRowNum][solvedColNum].value
	for rowNum := 0; rowNum < 9; rowNum++ {
		if rowNum == solvedRowNum || col.cells[rowNum].value != 0 {
			continue
		}
		col.cells[rowNum].removeCandidate(value)
	}
}
*/

func (g *Grid) ClearupInCol(solvedRowNum int, solvedColNum int) {
	col := g.cols[solvedColNum]
	value := g.cells[solvedRowNum][solvedColNum].value
	ClearupInUnit(col, solvedRowNum, value)
}

func (g *Grid) ClearupInBox(solvedRowNum int, solvedColNum int) {
	solvedBoxNum, solvedCellNum := calcBoxAndCellNum(solvedRowNum, solvedColNum)
	value := g.cells[solvedRowNum][solvedColNum].value
	box := g.boxes[solvedBoxNum]
	ClearupInUnit(box, solvedCellNum, value)
}

func (g *Grid) Clearup() {
	for rowNum := 0; rowNum < 9; rowNum++ {
		for colNum := 0; colNum < 9; colNum++ {
			if g.cells[rowNum][colNum].value != 0 {
				g.ClearupInRow(rowNum, colNum)
				g.ClearupInCol(rowNum, colNum)
				g.ClearupInBox(rowNum, colNum)
			}
		}
	}
}

func (g *Grid) HiddenSingleInUnit(u House) (value uint8, num int) {
	var rev [9][9]bool
	var freq [9]uint8

	for i := 0; i < 9; i++ {
		for j := uint8(0); j < 9; j++ {
			if u.cells[i].value == 0 && u.cells[i].candidates[j] {
				rev[j][i] = true
				freq[j] += 1
			}
		}
	}

	for j := 0; j < 9; j++ {
		if freq[j] != 1 {
			continue
		}
		value = uint8(j) + 1
		for num = 0; num < 9; num++ {
			if rev[j][num] {
				return
			}
		}
	}
	return
}

func (g *Grid) HiddenSingleInRows() (used bool) {
	for rowNum := 0; rowNum < 9; rowNum++ {
		value, colNum := g.HiddenSingleInUnit(g.rows[rowNum])
		if value != 0 {
			g.Set(rowNum, colNum, value)
			return true
		}
	}
	return false
}

func (g *Grid) HiddenSingleInCols() (used bool) {
	for colNum := 0; colNum < 9; colNum++ {
		value, rowNum := g.HiddenSingleInUnit(g.cols[colNum])
		if value != 0 {
			g.Set(rowNum, colNum, value)
			return true
		}
	}
	return false
}

func (g *Grid) HiddenSingleInBoxes() (used bool) {
	for boxNum := 0; boxNum < 9; boxNum++ {
		value, cellNum := g.HiddenSingleInUnit(g.boxes[boxNum])
		if value != 0 {
			rowNum, colNum := calcRowAndColNum(boxNum, cellNum)
			g.Set(rowNum, colNum, value)
			return true
		}
	}
	return false

}

func (g *Grid) NakedSingle() (used bool) {
	for rowNum := 0; rowNum < 9; rowNum++ {
		for colNum := 0; colNum < 9; colNum++ {
			if g.cells[rowNum][colNum].value == 0 && g.cells[rowNum][colNum].candidateCount == 1 {
				for i, candidate := range g.cells[rowNum][colNum].candidates {
					if candidate {
						value := uint8(i) + 1
						g.Set(rowNum, colNum, value)
						return true
					}
				}
				//value = g.cells[rowNum][colNum].value
				//return
			}
		}
	}
	return false
}
